home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / v9n19.arc / FILEBUF.C < prev    next >
C/C++ Source or Header  |  1990-10-13  |  13KB  |  453 lines

  1. // filebuf.c RHS 9/1/90 file-buffering and handling routines
  2.  
  3. #ifdef WINDOWS
  4. #include<windows.h>
  5. #include"wsmooth.h"
  6. #include"wsmooth2.h"
  7. #endif
  8.  
  9. #include<stdio.h>
  10. #include<stdlib.h>
  11. #include<string.h>
  12. #include<malloc.h>
  13. #include<dos.h>
  14. #include<fcntl.h>
  15. #include<sys\types.h>
  16. #include<sys\stat.h>
  17. #include<io.h>
  18. #include"filebuf.h"
  19.  
  20. #define TRUE    1  
  21. #define FALSE   0
  22. #define MAXSCREEN   25
  23. #define CTRL_Z      0x1A
  24. #define CR          '\r'
  25. #define LF          '\n'
  26. #define MYEOF       0xffff
  27.  
  28. #define PAGEINDEXSIZE   50
  29. #define HALFBUFFER      (30*1024)
  30. #define MAXFILESIZE     ((long)PAGEINDEXSIZE*(long)HALFBUFFER)
  31. #define BUFFERSIZE      (HALFBUFFER*2)
  32.  
  33. #if defined(WINDOWS)
  34. HANDLE indexbufhdl = NULL, bufferhdl = NULL;
  35. extern HWND WinSmooth;
  36. #endif
  37.  
  38. unsigned far *lineptr;              // pointer to line index in index segment
  39. unsigned far *pageptr;              // pointer to page index in index segment
  40. unsigned far *indexstart = NULL;    // pointer to start of line index
  41. unsigned far *indexbuf = NULL;      // pointer to index buffer
  42. char far *fileptr = NULL;           // pointer to curr line
  43. char far *bufstart = NULL;          // pointer to start of filebuffer
  44. char far *bufend;                   // point to end of buffer
  45. int fh = -1;
  46. int stripbits = FALSE;
  47.  
  48. void filebuf_updateindex(int endndx);
  49. void filebuf_read(void);
  50. void filebuf_nextbuffer(void);
  51. void filebuf_prevbuffer(void);
  52. void filebuf_reset(void);
  53. void filebuf_stripbits(char far *buf, unsigned len);
  54. void error_exit(int err, char *msg);
  55.  
  56. BOOL filebuf_fileisopen(void)
  57.     {
  58.     if(fh != -1)
  59.         return TRUE;
  60.     return FALSE;
  61.     }
  62.  
  63.     // toggles bit stripping flag
  64. void filebuf_strip(int strip)
  65.     {
  66.     stripbits = strip;
  67.     }
  68.  
  69.    // strips high bit from bytes read
  70. void filebuf_stripbits(char far *buf, unsigned len)
  71.     {
  72.     if(!stripbits)
  73.         return;
  74.     for( ; len; len--)
  75.         buf[len-1] &= 0x7f;
  76.     }
  77.  
  78.    // initializes file buffers
  79. int filebuf_init(void)
  80.     {
  81.     if(indexbufhdl && bufferhdl)
  82.         {
  83.         filebuf_reset();
  84.         return TRUE;
  85.         }
  86.  
  87.         // allocate index buffer and file buffer
  88. #ifdef WINDOWS
  89.     {
  90.     unsigned u = BUFFERSIZE+1;          // use an unsigned to get over compiler bug
  91.                                         // allocate index and file buffers
  92.     if(indexbufhdl = GlobalAlloc(GMEM_MOVEABLE,u))
  93.         indexbuf = (unsigned far *)GlobalWire(indexbufhdl);
  94.  
  95.     if(bufferhdl = GlobalAlloc(GMEM_MOVEABLE,u))
  96.         bufstart = (char far *)GlobalWire(bufferhdl);
  97.  
  98.     if(!indexbufhdl || !bufferhdl)
  99.         {
  100.         Message(WinSmooth,"Unable to allocate memory buffers: hdls=%u,%u ptrs=%lp,%lp size=%ld",
  101.             indexbufhdl,bufferhdl,indexbuf,bufstart,GlobalSize(indexbufhdl));
  102.         return FALSE;
  103.         }
  104.     }
  105.  
  106.     if(!indexbuf || !bufstart)
  107.         Message(WinSmooth,"Unable to re-locate memory buffers: ptrs=%lp,%lp",
  108.             indexbuf,bufstart);
  109. #else
  110.     indexbuf = (unsigned far *)_fmalloc(BUFFERSIZE+1);
  111.     bufstart = (char far *)_fmalloc(BUFFERSIZE+1);
  112.     if(!indexbuf || !bufstart)
  113.         error_exit(0,"No buffer allocation");
  114. #endif
  115.  
  116.         // set line pointer to beginning of line index
  117.     indexstart = lineptr = &indexbuf[PAGEINDEXSIZE];
  118.         // set page pointer to beginning of page index
  119.     pageptr = indexbuf;
  120.         // initialize indexes
  121.     _fmemset(indexbuf,0x0000,BUFFERSIZE);
  122.         // set last word of line index to MYEOF
  123.     indexbuf[BUFFERSIZE/(sizeof(unsigned))] = MYEOF;
  124.  
  125.     return TRUE;
  126.     }
  127.  
  128.    // resets variables for new file without re-allocating buffers
  129. void filebuf_reset(void)
  130.     {
  131.     lineptr = indexstart;
  132.     pageptr = indexbuf;
  133.     fileptr = NULL;
  134.     _fmemset(indexbuf,0x0000,BUFFERSIZE);
  135.     }
  136.  
  137. int filebuf_open(char *filename, int strip)
  138.     {
  139.     if(!(*filename))
  140.         return FALSE;
  141.  
  142. #ifdef WINDOWS
  143.     {
  144.     OFSTRUCT of;
  145.         // open the file for read only, and allow others to read it (but not write)
  146.     if((fh = OpenFile(filename,&of,
  147.             OF_CANCEL | OF_PROMPT | OF_READ | OF_SHARE_DENY_WRITE)) == -1)
  148.         {
  149.         Message(WinSmooth,"Error %d opening %s",of.nErrCode,filename);
  150.         return FALSE;
  151.         }
  152.     }
  153. #else
  154.     if((fh = open(filename,O_BINARY | O_RDONLY)) == -1)
  155.         error_exit(0,"Unable to open file");
  156. #endif
  157.     {
  158.     struct stat s;
  159.  
  160.     if(fstat(fh,&s))                    // get file size
  161.         return FALSE;
  162.     if(s.st_size > MAXFILESIZE)         // check file size
  163. #ifdef WINDOWS
  164.         {
  165.         Message(WinSmooth,"%s is too large to be handled by WinSmooth",
  166.             filename);
  167.         return FALSE;
  168.         }
  169. #else
  170.         error_exit(0,"File too large");
  171. #endif
  172.     }
  173.  
  174.     filebuf_read();                     // get first buffer from file
  175.  
  176.     {
  177.     unsigned len;                       // read entire file
  178.     for(len = 1; filebuf_nextline(&len) && len; );
  179.     }
  180.  
  181.     stripbits = (strip ? TRUE : FALSE);
  182.     return TRUE;
  183.     }
  184.  
  185.    // de-allocates filebuffers and cleans up
  186. void filebuf_destruct(void)
  187.     {
  188. #if defined(WINDOWS)
  189.     if(indexbufhdl)
  190.         {
  191.         GlobalUnWire(indexbufhdl);
  192.         GlobalFree(indexbufhdl);
  193.         }
  194.     if(bufferhdl)
  195.         {
  196.         GlobalUnWire(bufferhdl);
  197.         GlobalFree(bufferhdl);
  198.         }
  199.     indexbufhdl = bufferhdl = NULL;
  200. #else
  201.     if(indexbuf)
  202.         _ffree(indexbuf);
  203.     if(bufstart)
  204.         _ffree(bufstart);
  205.     bufstart = NULL;
  206.     indexbuf = NULL;
  207. #endif
  208.     if(fh != -1)
  209.         close(fh);
  210.     fh = -1;
  211.     }
  212.  
  213.    // reads buffer from file
  214. void filebuf_read(void)
  215.     {
  216.     unsigned bytes;
  217.  
  218.     lseek(fh,(HALFBUFFER*(pageptr-indexbuf)),SEEK_SET);
  219.     _dos_read(fh,&bufstart[HALFBUFFER],HALFBUFFER,&bytes);
  220.     filebuf_stripbits(&bufstart[HALFBUFFER],HALFBUFFER);
  221.  
  222.     fileptr = (!fileptr ? &bufstart[HALFBUFFER] : (fileptr -= HALFBUFFER));
  223.  
  224.     bufend = &bufstart[HALFBUFFER+bytes];        // set to end of buffer
  225.     *bufend = CTRL_Z;
  226.     filebuf_updateindex((bytes != HALFBUFFER) ? TRUE : FALSE);
  227.     }
  228.  
  229.    // updates line index for buffer
  230. void filebuf_updateindex(int endndx)
  231.     {
  232.     char far *buf = fileptr;
  233.     char far *old = fileptr;
  234.     unsigned far *ndx = lineptr;
  235.     unsigned numlines = ((pageptr == indexbuf) ? 0 : pageptr[-1]);
  236.  
  237.     while(buf <= bufend)                // until end of buffer
  238.         switch(*buf)
  239.             {
  240.             case CR:                    // if CR or LF found
  241.             case LF:
  242.                 buf++;                  // check next character
  243.                 if(*buf == LF)          // if CR followed by line feed
  244.                     buf++;
  245.                 *ndx++ = (buf-old);     // use ptr arithmetic to get length
  246.                 numlines++;
  247.                 old = buf;              // set old to next line
  248.                 if(buf == bufend)
  249.                     buf++;
  250.                 break;                  // break so as not to fall thru
  251.             case CTRL_Z:
  252.                 bufend = buf;           // CTRL_Z found, set new buf end
  253.                 if(buf > old)           // if line ends with CTRL_Z
  254.                     *ndx++ = 0;
  255.                 buf++;
  256.                 break;
  257.             default:
  258.                 buf++;
  259.                 break;
  260.             }
  261.     *pageptr = numlines;                // set to accumulated line count
  262.     if(endndx)                          // if end of file reached
  263.         *ndx = MYEOF;                   // set end of file marker in index
  264.     }
  265.  
  266.    // read next buffer from file
  267. void filebuf_nextbuffer(void)
  268.     {
  269.         // copy the 2nd half of buffer to the 1st half
  270.     _fmemcpy(bufstart,&bufstart[HALFBUFFER],HALFBUFFER);
  271.     pageptr++;                          // set for next page
  272.  
  273.         // read HALFBUFFER bytes into 2nd half
  274.     filebuf_read();
  275.     }
  276.  
  277.    // read previous buffer from file
  278. void filebuf_prevbuffer(void)
  279.     {
  280.     if(pageptr == indexbuf)             // insure we're not on 1st page
  281.         return;
  282.                                         // copy 1st buffer to 2nd
  283.     _fmemcpy(&bufstart[HALFBUFFER],bufstart,HALFBUFFER);
  284.     fileptr += HALFBUFFER;              // adjust pointer to its position in 2nd page
  285.     pageptr--;                          // seek to page
  286.     lseek(fh,(HALFBUFFER*(pageptr-indexbuf)),SEEK_SET);
  287.     {
  288.     unsigned bytes;
  289.     _dos_read(fh,bufstart,HALFBUFFER,&bytes); // read the file into the 1st buffer
  290.     filebuf_stripbits(bufstart,HALFBUFFER);
  291.     }   
  292.     bufend = &bufstart[BUFFERSIZE];     // set to end of buffer
  293.     *bufend = CTRL_Z;
  294.     }
  295.  
  296.    // seek to a particular line
  297. void filebuf_seekline(unsigned line)
  298.     {       
  299.     unsigned far *page = indexbuf, far *buf1, far *buf2, far *ndx;
  300.  
  301.         // find a page with a higher accum. line count
  302.     for( ; line > *page && *page; page++);
  303.  
  304.     if(page == indexbuf)                // if we're on the first page (no prev. page)
  305.         {
  306.         buf1 = page;                    // set for first 2 buffers
  307.         buf2 = page+1;
  308.         }
  309.     else if(*(page+1) == 0)             // or not on 1st page and next page is empty
  310.         {
  311.         buf1 = page-1;                  // set for this and prev buffer
  312.         buf2 = page;
  313.         }
  314.     else                                // or we are between two real pages
  315.         {
  316.         if(line > (*(page-1) + ((*(page+1) - *(page-1)) / 2)))
  317.             {
  318.             buf1 = page;
  319.             buf2 = page+1;
  320.             }
  321.         else
  322.             {
  323.             buf1 = page-1;
  324.             buf2 = page;
  325.             }
  326.         }
  327.     lineptr = indexstart+line;          // set lineptr to the line
  328.     pageptr = page;                     // set pageptr to the page
  329.  
  330.     if(*buf2)                           // if no 2nd page, nothing to read
  331.         {
  332.         unsigned bytes;
  333.                                         // read 1st buffer
  334.         lseek(fh,(HALFBUFFER*(buf1-indexbuf)),SEEK_SET);
  335.         _dos_read(fh,bufstart,HALFBUFFER,&bytes);
  336.         lseek(fh,(HALFBUFFER*(buf2-indexbuf)),SEEK_SET);
  337.         _dos_read(fh,&bufstart[HALFBUFFER],HALFBUFFER,&bytes);
  338.         filebuf_stripbits(bufstart,HALFBUFFER*2);
  339.         bufend = &bufstart[HALFBUFFER+bytes];  // set to end of buffer
  340.         *bufend = CTRL_Z;
  341.         fileptr = (page == buf1) ? bufstart : &bufstart[HALFBUFFER];
  342.         }
  343.     else
  344.         fileptr = &bufstart[HALFBUFFER];
  345.     ndx = indexstart;
  346.     ndx += ((pageptr == indexbuf) ? 0 : *(pageptr-1));
  347.  
  348.     if(*buf2)
  349.         if(fileptr != bufstart)
  350.             {
  351.             while(fileptr[-1] != CR && fileptr[-1] != LF)
  352.                 fileptr--;
  353.             }
  354.         else if(lineptr != indexstart)
  355.             {
  356.             ndx++;
  357.             while(fileptr[1] != CR && fileptr[1] != LF)
  358.                 fileptr++;
  359.             fileptr++;
  360.             while(*fileptr == CR || *fileptr == LF)
  361.                 fileptr++;
  362.             }
  363.     for(; ndx < lineptr; fileptr += *ndx, ndx++)
  364.             ;
  365.     }
  366.  
  367.     // get next line from file
  368. char far *filebuf_nextline(unsigned *len)
  369.     {
  370.     char far *linestart;
  371.     char far *bufptr;                   // local pointer
  372.  
  373.     *len = 0;
  374.  
  375.     if(*lineptr == MYEOF)
  376.         return NULL;
  377. reset:
  378.     linestart = fileptr;                // set linestart to fileptr
  379.         // read until buffer end encountered, or until CR found
  380.     for( bufptr = fileptr; bufptr != bufend; bufptr++)
  381.         if((*bufptr == CR) || (*bufptr == LF))
  382.             break;
  383.     if(bufptr == bufend)                // end of buffer, line carries over
  384.         {
  385.         filebuf_nextbuffer();           // read more of file
  386.         goto reset;
  387.         }
  388.     *len = (bufptr-fileptr);            // remove CR from buf
  389.     fileptr += *lineptr++;
  390.     return linestart;
  391.     }
  392.  
  393.  
  394.    // get previous line from file
  395. char far *filebuf_prevline(unsigned *len)
  396.     {
  397.     char far *bufptr;
  398.     
  399.     *len = 0;
  400.  
  401.     if(lineptr == indexstart)           // if at beginning of file
  402.         return NULL;
  403.  
  404.     --lineptr;                          // set to previous line
  405.     bufptr = bufstart+HALFBUFFER;
  406.     if((fileptr > bufptr) && ((fileptr - *lineptr) <= bufptr))
  407.         pageptr--;                      // set to prev page
  408.     if((bufstart + *lineptr) > fileptr) // if line length extends from previous page
  409.         filebuf_prevbuffer();
  410.     fileptr -= (*lineptr);
  411.  
  412.     for(bufptr = fileptr; bufptr != bufend; bufptr++)
  413.         if((*bufptr == CR) || (*bufptr == LF))
  414.             break;
  415.     *len = (bufptr - fileptr);
  416.     return fileptr;
  417.     }
  418.  
  419.    // returns number of lines line file
  420. unsigned filebuf_numlines(void)
  421.     {
  422.     unsigned far *page;
  423.  
  424.     for(page = indexbuf; *(page+1); page++)
  425.         ;
  426.     return *page;
  427.     }
  428.  
  429.    // returns length of longest line in file
  430. unsigned filebuf_longestline(void)
  431.     {
  432.     unsigned far *ndx = indexstart;
  433.     unsigned longest = 0;
  434.  
  435.     for( ; *ndx != MYEOF; ndx++)
  436.         if(*ndx > longest)
  437.             longest = *ndx;
  438.     return longest;
  439.     }
  440.  
  441.    // exit routine on fatal error
  442. void error_exit(int err, char *msg)
  443.     {
  444. #if defined(WINDOWS)
  445.     extern HWND WinSmooth;
  446.  
  447.     Message(WinSmooth,msg);
  448. #else
  449.     printf("%s\n",msg);
  450. #endif
  451.     exit(err);
  452.     }
  453.